/* ----------------------------------------------------------------------------
* File: quiz_timer.cpp
*
* Desc: Timer object for quiz
*
* Created: 29/06/2011, by Alexey Korshunov
* ---------------------------------------------------------------------------- */
#include "quiz_timer.h"
#include "debug_logger.h"

#define WAIT_CORRECT_ANSWER	20 * 1000		// 1 min


namespace QuizCore
{
	QuizTimer::QuizTimer(QuizController* parent, fpTimeoutCallback callback)
		: m_Parent(parent)
		, m_TimeoutCallback(callback)
		, m_QuestionEvent(NULL)
		, m_AnswerEvent(NULL) 
	{
		// Create debug logger
		m_Logger = Common::CreateDebugLogger();
		if (!m_Logger.get())
			throw Common::Exception("QuizTimerThread: ERROR - Unable to create logger");

		m_QuestionEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL);
		if (m_QuestionEvent == NULL)
		{
			m_Logger->Print("QuizTimer: ERROR - Unable to create question event");
			throw Common::Exception("QuizTimer: ERROR - Unable to create question event");
		}

		m_AnswerEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL);
		if (m_AnswerEvent == NULL)
		{
			m_Logger->Print("QuizTimer: ERROR - Unable to create answer event");
			throw Common::Exception("QuizTimer: ERROR - Unable to create answer event");
		}
	}

	QuizTimer::~QuizTimer()
	{
		::CloseHandle(m_QuestionEvent);
		::CloseHandle(m_AnswerEvent);
	}

	Common::Error QuizTimer::Run()
	{
		DWORD dwEvent;
		HANDLE events[2];

		m_Logger->Print("QuizTimer: start");

		while(!QueryExitStatus(0))
		{
			// wait question event or stop
			events[0] = m_QuestionEvent;
			events[1] = m_hEventUserAbort;
			dwEvent = WaitForMultipleObjects(2, (const HANDLE*)events, FALSE, INFINITE);
			switch(dwEvent)
			{
			case WAIT_OBJECT_0:			// new question
				ResetEvent(m_QuestionEvent);
				m_Logger->Print("QuizTimer: new question");

				// calculate timeout
				events[0] = m_AnswerEvent;
				events[1] = m_hEventUserAbort;
				dwEvent = WaitForMultipleObjects(2, (const HANDLE*)events, FALSE, WAIT_CORRECT_ANSWER);
				if (dwEvent == WAIT_OBJECT_0)
				{
					// correct answer
					ResetEvent(m_AnswerEvent);
					m_Logger->Print("QuizTimer: correct answer");
				}
				else if (dwEvent == WAIT_OBJECT_0 + 1)
				{
					// stop event
				}
				else if (dwEvent == WAIT_TIMEOUT)
				{
					// timeout
					(*this->m_TimeoutCallback)((void*)m_Parent);
					m_Logger->Print("QuizTimer: timeout, %d sec", WAIT_CORRECT_ANSWER / 1000);
				}
				break;

			case WAIT_OBJECT_0 + 1:		// stop
				break;

			default:
				break;
			}
		}

		m_Logger->Print("QuizTimer: stop");
		return Common::SKYPE_SUCCESS;
	}

	Common::Error QuizTimer::SignalNewQuestion()
	{
		::SetEvent(m_QuestionEvent);
		return Common::SKYPE_SUCCESS;
	}

	Common::Error QuizTimer::SignalCorrectAnswer()
	{
		::SetEvent(m_AnswerEvent);
		return Common::SKYPE_SUCCESS;
	}

	Common::Error QuizTimer::Start()
	{
		return (StartThread() ? Common::SKYPE_SUCCESS : Common::SKYPE_ERROR);
	}

	Common::Error QuizTimer::Stop()
	{
		StopThread();
		return Common::SKYPE_SUCCESS;
	}
}